﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace Legend
{
    /// <summary>
    /// Provides the base implementation for a type converter that converts between
    /// two types, only the abstract methods has to be implemented for a fully working
    /// type converter.
    /// </summary>
    /// <typeparam name="TSource">The source type of the converter.</typeparam>
    /// <typeparam name="TDestination">The destination type of the converter.</typeparam>
    public abstract class TypeConverterBase<TSource, TDestination>
        : TypeConverter
    {
        
        /// <summary>
        /// Gets whether the converter can convert from the source type to
        /// the type specified.
        /// </summary>
        /// <param name="context">The context of the converter.</param>
        /// <param name="destinationType">The type to check.</param>
        /// <returns>True if a conversion can be made.</returns>
        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            if (destinationType.Equals(typeof(TDestination)))
            {
                return true;
            }

            return base.CanConvertTo(context, destinationType);
        }

        /// <summary>
        /// Gets whether the converter can convert to the source type of the converter to
        /// the type specified.
        /// </summary>
        /// <param name="context">The context of the converter.</param>
        /// <param name="sourceType">The type to check.</param>
        /// <returns>True if a conversion can be made.</returns>
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            if (sourceType.Equals(typeof(TDestination)))
            {
                return true;
            }

            return base.CanConvertFrom(context, sourceType);
        }

        /// <summary>
        /// Converts from the source type to the destination type.
        /// </summary>
        /// <param name="value">The value to convert.</param>
        /// <returns>The converted value.</returns>
        public TDestination ConvertTo(TSource value)
        {
            return (TDestination)this.ConvertTo(value, typeof(TDestination));
        }

        /// <summary>
        /// Converts to the source type of the converter from the destination type.
        /// </summary>
        /// <param name="value">The value to convert.</param>
        /// <returns>The converted value.</returns>
        public TSource ConvertFrom(TDestination value)
        {
            return (TSource)base.ConvertFrom(value);
        }

        ///<summary>
        /// Converts the given object to the type of this converter, using the specified
        /// context and culture information.
        /// </summary>
        /// <param name="context">An System.ComponentModel.ITypeDescriptorContext that provides a format context.</param>
        /// <param name="culture">The System.Globalization.CultureInfo to use as the current culture.</param>
        /// <param name="value">The System.Object to convert.</param>
        /// <returns>An System.Object that represents the converted value.</returns>
        /// <exception cref="NotSupportedException">The conversion cannot be performed.</exception>
        public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
        {
            if (value is TDestination)
            {
                return this.ConvertFrom(context, culture, (TDestination)value);
            }

            throw new NotSupportedException("The value is not of the type specified in the TDestination generic type argument.");
        }

        /// <summary>
        /// Converts the given value object to the specified type, using the specified
        /// context and culture information.
        /// </summary>
        /// <param name="context">An System.ComponentModel.ITypeDescriptorContext that provides a format context.</param>
        /// <param name="culture">A System.Globalization.CultureInfo. If null is passed, the current culture
        /// is assumed.</param>
        /// <param name="value">The value to convert.</param>
        /// <param name="destinationType">The System.Type to convert the value parameter to.</param>
        /// <returns>An System.Object that represents the converted value.</returns>
        /// <exception cref="ArgumentNullException">System.ArgumentNullException: The destinationType parameter is null.</exception>
        /// <exception cref="NotSupportedException">The conversion cannot be performed.</exception>
        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
        {
            if (destinationType.Equals(typeof(TDestination)))
            {
                return this.ConvertTo(context, culture, (TSource)value);
            }
            
            throw new NotSupportedException("The specified destination type is not supported.");
        }

        protected abstract TSource ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, TDestination value);
        protected abstract TDestination ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, TSource value);
        
    }
}